package com.invengo.device;

import android.annotation.SuppressLint;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.text.TextUtils;
import android.util.Log;

import com.invengo.library_rfid.VoiceManager;
import com.invengo.library_rfid.analyze.EPCAnalyzeFactory;
import com.invengo.library_rfid.analyze.EPCStrategy;
import com.invengo.library_rfid.analyze._EpcRuleTag;
import com.invengo.library_rfid.classify.AnalyzeImpl;
import com.invengo.library_rfid.classify.BlueBean;
import com.invengo.library_rfid.classify.RfidModelImpl;
import com.invengo.library_rfid.device.IDevice;
import com.rfid.api.ADReaderInterface;
import com.rfid.def.ApiErrDefinition;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java8.util.Optional;
import me.goldze.mvvmhabit.bus.RxBus;
import me.goldze.mvvmhabit.bus.RxSubscriptions;
import me.goldze.mvvmhabit.http.interceptor.logging.LocalLogUtil;

import me.goldze.mvvmhabit.utils.KLog;
import me.goldze.mvvmhabit.utils.ToastUtils;
import me.goldze.mvvmhabit.utils.cache.ACache;
import me.goldze.mvvmhabit.utils.cache.AKey;

public class DeviceHelper implements IDevice {
    private String cacheKey;

    private RfidModelImpl rfidModel;//标签类型更改
    private EPCStrategy ruleStrategy; //标签解析方案

    protected ExecutorService mThreadService;

    private VoiceManager voiceManager;

    private boolean mVoice = true;

    private AnalyzeImpl analyze = AnalyzeImpl.TO_BOOK; //解析类型，比如book，shelf，tid

    public ADReaderInterface reader;

    public VoiceManager getVoiceManager() {
        return voiceManager;
    }

    private String blueName;

    private Thread m_inventoryThrd;

    private DeviceHelper() {
        blueName = ACache.getInstance().getAsString(AKey.BLUETOOTH_NAME);
        reader = new ADReaderInterface();
        ruleStrategy = EPCAnalyzeFactory.getInstance().getRuleStrategy();
        rfidModel = RfidModelImpl.getDefaultModel();
        System.out.println("设置默认模型及标签：[ " + ruleStrategy.getRule().getRuleName() + " ]  [ " + rfidModel.name() + " ]");
        mThreadService = Executors.newCachedThreadPool();
    }

    public static DeviceHelper instance;

    public static DeviceHelper getInstance() {
        if (instance == null) synchronized (DeviceHelper.class) {
            if (instance == null) {
                instance = new DeviceHelper();
            }
        }
        return instance;
    }

    @Override
    public void init(Application application) {
        voiceManager = VoiceManager.getInstance(application);
//        ParamerManager.getInstance().initDefaultConfig(application);
        this.ruleStrategy = EPCAnalyzeFactory.getInstance().getEPCStrategy(_EpcRuleTag.RULE_FuNing);
        this.rfidModel = RfidModelImpl.U_DATA;
        RxSubscriptions.add(RxBus.getDefault().toObservable(_EpcRuleTag.class).subscribe(ruleTag -> {
            Log.w(getClass().getSimpleName(), "解析模型切换 >>>： " + ruleTag.getRuleName());
            this.ruleStrategy = EPCAnalyzeFactory.getInstance().getEPCStrategy(ruleTag);
        }));

        RxSubscriptions.add(RxBus.getDefault().toObservable(AnalyzeImpl.class).subscribe(analyzeModel -> {
            Log.w(getClass().getSimpleName(), "图书层标切换 >>>： " + analyzeModel.getName());
            this.analyze = analyzeModel;
        }));

        RxSubscriptions.add(RxBus.getDefault().toObservable(RfidModelImpl.class).subscribe(rfidModel -> {
            Log.w(getClass().getSimpleName(), "标签类型切换 >>>： " + rfidModel.getName());
            this.rfidModel = rfidModel;
        }));

        RxSubscriptions.add(RxBus.getDefault().toObservable(BlueBean.class).subscribe(bean -> {
            Log.w(getClass().getSimpleName(), "切换配对蓝牙 >>>： " + bean.getName());
            this.blueName = bean.getName();
            openDevice();
        }));
        openDevice();
    }

    Disposable subscribe;

    @Override
    public void openDevice() {
        if (TextUtils.isEmpty(blueName)) {
            LocalLogUtil.device2Log("没有配置蓝牙设备，请到设置中选择正确的设备！");
            showConnectError("没有配置蓝牙设备，请到设置中选择正确的设备！");
            return;
        }
        if (subscribe != null && !subscribe.isDisposed()) {
            subscribe.dispose();
            subscribe = null;
        }
        if (reader == null)
            reader = new ADReaderInterface();
        try {
            reader.RDR_Close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        checkInterval();
        KLog.e("开始准备连接。。。。" + blueName);
        subscribe = Observable.interval(500, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .subscribe(aLong -> {
                    if (reader.isReaderOpen()) {
                        LocalLogUtil.device2Log(blueName + "设备已经链接。。。。");
                        System.out.println("设备已经链接。。。。");
                        subscribe.dispose();
                        RxBus.getDefault().post(Boolean.TRUE);
                    } else {
                        if (aLong > 2) {
                            RxBus.getDefault().post(Boolean.FALSE);
                            subscribe.dispose();
                            showConnectError("蓝牙设备多次连接不成功，登录后请到设置->RFID设置->蓝牙中选择正确的设备");
                            LocalLogUtil.device2Log("多次尝试不成功，取消链接：" + blueName + "  " + aLong);
                            System.out.println("多次尝试不成功，取消链接：" + blueName + "  " + aLong);
                        } else {
                            LocalLogUtil.device2Log("设备未连接：" + blueName + "  " + aLong);
                            System.out.println("设备未连接：" + blueName + "  " + aLong);
                            reader.RDR_Open("RDType=RPAN;CommType=BLUETOOTH;Name=" + blueName);
                        }
                    }
                });
    }

    private Disposable connectInterval;

    private void checkInterval() {
        if (connectInterval == null)
            connectInterval = Observable.interval(1000, TimeUnit.MILLISECONDS)
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .subscribe(aLong -> {
                        if (aLong % 5 == 0) {
                            RxBus.getDefault().post(reader.isReaderOpen());
                        }
                    });
    }


    private void showConnectError(String message) {
        Observable.just(message)
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> ToastUtils.showLong(s));
    }

    @Override
    public void closeDevice() {
        try {
            reader.RDR_Close();
            reader = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    ThreadInterface threadRunnable;

    @Override
    public void startScan(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
        System.out.println("当前缓存[" + cacheKey + "] ==》" + strings);
        analyze.cache.put(cacheKey, strings);
        if (!reader.isReaderOpen()) {
            ToastUtils.showShort("没有链接设备，请到设置界面选择正确的蓝牙设备！");
            return;
        }
        if (isReading()) {
//            KLog.e("有残留的扫描程序，先取消掉。。。。");
            stopScan();
        }

        if (ACache.getInstance().getAsBoolean(AKey.IS_HOST_CONTROL)) {
            threadRunnable = new ThreadHostControl(reader, callback);
        } else {
            threadRunnable = new ThreadAutoScan(reader, callback);
        }
        m_inventoryThrd = new Thread(threadRunnable);
        m_inventoryThrd.start();
    }

    private ScanCallback callback = (uid, udata) -> {
        KLog.e("uid:  " + uid + "    udata: " + udata);
        analyze.apply(uid, udata, rfidModel, ruleStrategy, cacheKey);
    };

    @Override
    public void stopScan() {
//        KLog.e("执行停止扫描");
        reader.RDR_SetCommuImmeTimeout();
        if (threadRunnable != null) {
            threadRunnable.setThreadRun(false);
        }
        try {
            if (m_inventoryThrd != null)
                m_inventoryThrd.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        m_inventoryThrd = null;
    }

    @Override
    public boolean checkReaderConnection() {
        reader.RDR_Close();
        String conStr = "RDType=RPAN;CommType=BLUETOOTH;Name=" + blueName;
        int res = reader.RDR_Open(conStr);
        return res == ApiErrDefinition.NO_ERROR;
    }

    @Override
    public void changeAnalyzeModel(AnalyzeImpl analyzeModel) {
        this.analyze = analyze;
    }

    public boolean checkReadStatus(String btName) {
        boolean flag;
        //先关闭连接
        reader.RDR_Close();
        String conStr = "RDType=RPAN;CommType=BLUETOOTH;Name=" + btName;
        int res = reader.RDR_Open(conStr);
        if (res != ApiErrDefinition.NO_ERROR) {
            flag = false;
        } else {
            flag = true;
        }
        return flag;
    }

    @Override
    public void cleanCache(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
        System.out.print("清除之前的缓存[" + cacheKey + "] ==》" + strings);
        strings.clear();
        System.out.println("清除之后的缓存[" + cacheKey + "] ==》" + strings);
        analyze.cache.put(cacheKey, strings);
    }

    public List<String> getCache(String cacheKey) {
        return analyze.cache.get(cacheKey);
    }

    @Override
    public boolean isReading() {
        if (threadRunnable == null)
            return false;
        return threadRunnable.isThreadRun();
    }

    @Override
    public int[] getPowerMeter() {
        return new int[0];
    }

    @Override
    public int[] getPower() {
        return new int[0];
    }

    public void changePower(Integer integer) {

    }


    @SuppressLint("NewApi")
    public void addTempCache(String cacheKey) {
        this.cacheKey = cacheKey;
        List<String> strings = Optional.ofNullable(analyze.cache.get(cacheKey)).orElseGet(ArrayList::new);
//        System.out.println("当前缓存[" + cacheKey + "] ==》" + strings);
        analyze.cache.put(cacheKey, strings);
    }

    @Override
    public void changeVoice(boolean needVoice) {
        ACache.getInstance().put(AKey.IS_OPEN_VOICE, needVoice);
        if (needVoice) {
            DeviceHelper.getInstance().getVoiceManager().playSuccessSound();
        }
        mVoice = needVoice;
    }

    @Override
    public void playVoice() {
        if (mVoice)
            DeviceHelper.getInstance().getVoiceManager().playSuccessSound();
    }

    @Override
    public void playOhterVoice() {
        if (mVoice)
            DeviceHelper.getInstance().getVoiceManager().playFailureSound();
    }

    public List<String> getDeviceList() {
        List<String> data = new ArrayList<>();
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
        if (devices.size() > 0) { //存在已配对过的设备
            //利用for循环读取每一个设备的信息
            for (Iterator<BluetoothDevice> it = devices.iterator(); it.hasNext(); ) {
                BluetoothDevice btd = it.next();
                data.add(btd.getName());
            }
        } else {
            //不存在已经配对的蓝牙设备
            System.out.println("未查找到蓝牙设备！");
        }
        return data;
    }
}
